using UnityEngine;  
using System.Collections; 
using System;
using System.Text;
using UnityEditor;  
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;

namespace AudioStudio
{
    
public class AnimationClipModify
 {
    public static bool UpdateFunctionName(AnimationClip clip)  
    {
        bool changed = UpdateEvents(clip);
        string clippath = AssetDatabase.GetAssetPath(clip);
        ModelImporter mi = AssetImporter.GetAtPath(clippath) as ModelImporter;
        if(mi == null)
        {
            return changed;
        }   
  
        bool replaced = false;
        SerializedObject serializedObject = new SerializedObject(mi);  
        SerializedProperty clipAnimations = serializedObject.FindProperty("m_ClipAnimations");  
        for (int i = 0; i < clipAnimations.arraySize; i++)  
        {
            AnimationClipInfoProperties clipInfoProperties = new AnimationClipInfoProperties(clipAnimations.GetArrayElementAtIndex(i));
            UnityEngine.AnimationEvent[] events = clipInfoProperties.GetEvents();
            foreach(UnityEngine.AnimationEvent e in events)
            {
                if(e.functionName == "Anim_Sound")
                {
                    e.functionName = "PlaySound";
                    replaced = true;
                    AkSoundEngine.LogWarning(string.Format("Update {0}'s {1} functionName to PlaySound",clippath,clipInfoProperties.name));
                }
            }
            if(replaced)
            {
                clipInfoProperties.SetEvents(events);  
            }
        }  
        if(replaced)
        {
            serializedObject.ApplyModifiedProperties();
            AssetDatabase.ImportAsset(clippath);
            return true;
        }
        return changed;
    }

    private static bool UpdateEvents(AnimationClip clip)
    {
        List<UnityEngine.AnimationEvent> events = new List<UnityEngine.AnimationEvent>();
        bool replaced = false;
        foreach(UnityEngine.AnimationEvent evt in clip.events)
        {
            if(evt.functionName == "Anim_Sound")
            {
                evt.functionName = "PlaySound";
                replaced = true;
            }
            events.Add(evt);
        }
        AnimationUtility.SetAnimationEvents(clip,events.ToArray());
        return replaced;
    }

    private static bool RefreshEvents(AnimationClip clip,XElement node)
    {
        List<UnityEngine.AnimationEvent> events = new List<UnityEngine.AnimationEvent>();
        foreach (UnityEngine.AnimationEvent evt in clip.events)
        {
            if (!AudioUtility.IsSoundAnimationEvent(evt))
            {
                events.Add(evt);
            }
        }
        
        foreach (var e in node.Descendants("AnimationEvent"))
        {
            UnityEngine.AnimationEvent animEvent = new UnityEngine.AnimationEvent();
            animEvent.time = AudioUtility.GetXmlPropertyAsInteger(e, "time") * 0.001f;
            animEvent.stringParameter = AudioUtility.GetXmlProperty(e, "paramString");
            animEvent.functionName = AudioUtility.GetXmlProperty(e, "functionName");
            events.Add(animEvent);
        }
        AnimationUtility.SetAnimationEvents(clip, events.ToArray());
        return true;
    }

    public static bool ImportEvents(AnimationClip clip,XElement node)
    {
        bool changed = RefreshEvents(clip,node);
        string clippath = AssetDatabase.GetAssetPath(clip);
        ModelImporter mi = AssetImporter.GetAtPath(clippath) as ModelImporter;
        if(mi == null)
        {
            return changed;
        }   
  
        SerializedObject serializedObject = new SerializedObject(mi);  
        SerializedProperty clipAnimations = serializedObject.FindProperty("m_ClipAnimations");  
        string clipName = AudioUtility.GetXmlProperty(node, "name");
        for (int i = 0; i < clipAnimations.arraySize; i++)  
        {
            AnimationClipInfoProperties clipInfoProperties = new AnimationClipInfoProperties(clipAnimations.GetArrayElementAtIndex(i));
            if(clipInfoProperties.name == clipName)
            {
                UnityEngine.AnimationEvent[] events = clipInfoProperties.GetEvents();
                List<UnityEngine.AnimationEvent> newevents = new List<UnityEngine.AnimationEvent>();
                foreach(UnityEngine.AnimationEvent e in events)
                {
                    if(!AudioUtility.IsSoundAnimationEvent(e))
                    {
                        newevents.Add(e);
                    }
                }
                foreach (var e in node.Descendants("AnimationEvent"))
                {
                    UnityEngine.AnimationEvent animEvent = new UnityEngine.AnimationEvent();
                    string keyframe = AudioUtility.GetXmlProperty(e, "keyframe");
                    animEvent.time = Convert.ToSingle(keyframe) / clip.frameRate;
                    animEvent.stringParameter = AudioUtility.GetXmlProperty(e, "paramString");
                    animEvent.functionName = AudioUtility.GetXmlProperty(e, "functionName");
                    newevents.Add(animEvent);
                }
                clipInfoProperties.SetEvents(newevents.ToArray());  
                serializedObject.ApplyModifiedProperties();
                AssetDatabase.ImportAsset(clippath);
                return true;
            }
        }
        return changed;
    }
}  
  
class AnimationClipInfoProperties  
{  
    SerializedProperty m_Property;  
  
    private SerializedProperty Get(string property) { return m_Property.FindPropertyRelative(property); }  
  
    public AnimationClipInfoProperties(SerializedProperty prop) { m_Property = prop; }  
  
    public string name { get { return Get("name").stringValue; } set { Get("name").stringValue = value; } }  
    public string takeName { get { return Get("takeName").stringValue; } set { Get("takeName").stringValue = value; } }  
    public float firstFrame { get { return Get("firstFrame").floatValue; } set { Get("firstFrame").floatValue = value; } }  
    public float lastFrame { get { return Get("lastFrame").floatValue; } set { Get("lastFrame").floatValue = value; } }  
    public int wrapMode { get { return Get("wrapMode").intValue; } set { Get("wrapMode").intValue = value; } }  
    public bool loop { get { return Get("loop").boolValue; } set { Get("loop").boolValue = value; } }  
  
    // Mecanim animation properties  
    public float orientationOffsetY { get { return Get("orientationOffsetY").floatValue; } set { Get("orientationOffsetY").floatValue = value; } }  
    public float level { get { return Get("level").floatValue; } set { Get("level").floatValue = value; } }  
    public float cycleOffset { get { return Get("cycleOffset").floatValue; } set { Get("cycleOffset").floatValue = value; } }  
    public bool loopTime { get { return Get("loopTime").boolValue; } set { Get("loopTime").boolValue = value; } }  
    public bool loopBlend { get { return Get("loopBlend").boolValue; } set { Get("loopBlend").boolValue = value; } }  
    public bool loopBlendOrientation { get { return Get("loopBlendOrientation").boolValue; } set { Get("loopBlendOrientation").boolValue = value; } }  
    public bool loopBlendPositionY { get { return Get("loopBlendPositionY").boolValue; } set { Get("loopBlendPositionY").boolValue = value; } }  
    public bool loopBlendPositionXZ { get { return Get("loopBlendPositionXZ").boolValue; } set { Get("loopBlendPositionXZ").boolValue = value; } }  
    public bool keepOriginalOrientation { get { return Get("keepOriginalOrientation").boolValue; } set { Get("keepOriginalOrientation").boolValue = value; } }  
    public bool keepOriginalPositionY { get { return Get("keepOriginalPositionY").boolValue; } set { Get("keepOriginalPositionY").boolValue = value; } }  
    public bool keepOriginalPositionXZ { get { return Get("keepOriginalPositionXZ").boolValue; } set { Get("keepOriginalPositionXZ").boolValue = value; } }  
    public bool heightFromFeet { get { return Get("heightFromFeet").boolValue; } set { Get("heightFromFeet").boolValue = value; } }  
    public bool mirror { get { return Get("mirror").boolValue; } set { Get("mirror").boolValue = value; } }  
  
    public UnityEngine.AnimationEvent GetEvent(int index)  
    {
        UnityEngine.AnimationEvent evt = new UnityEngine.AnimationEvent();  
        SerializedProperty events = Get("events");  
  
        if (events != null && events.isArray)  
        {  
            if (index < events.arraySize)  
            {  
                evt.floatParameter = events.GetArrayElementAtIndex(index).FindPropertyRelative("floatParameter").floatValue;  
                evt.functionName = events.GetArrayElementAtIndex(index).FindPropertyRelative("functionName").stringValue;  
                evt.intParameter = events.GetArrayElementAtIndex(index).FindPropertyRelative("intParameter").intValue;  
                evt.objectReferenceParameter = events.GetArrayElementAtIndex(index).FindPropertyRelative("objectReferenceParameter").objectReferenceValue;  
                evt.stringParameter = events.GetArrayElementAtIndex(index).FindPropertyRelative("data").stringValue;  
                evt.time = events.GetArrayElementAtIndex(index).FindPropertyRelative("time").floatValue;  
            }  
            else  
            {  
                Debug.LogWarning("Invalid Event Index");  
            }  
        }  
  
        return evt;  
    }  
  
    public void SetEvent(int index, UnityEngine.AnimationEvent animationEvent)  
    {  
        SerializedProperty events = Get("events");  
  
        if (events != null && events.isArray)  
        {  
            if (index < events.arraySize)  
            {  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("floatParameter").floatValue = animationEvent.floatParameter;  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("functionName").stringValue = animationEvent.functionName;  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("intParameter").intValue = animationEvent.intParameter;  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("objectReferenceParameter").objectReferenceValue = animationEvent.objectReferenceParameter;  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("data").stringValue = animationEvent.stringParameter;  
                events.GetArrayElementAtIndex(index).FindPropertyRelative("time").floatValue = animationEvent.time;  
            }  
  
            else  
            {  
                Debug.LogWarning("Invalid Event Index");  
            }  
        }  
    }  
  
  
    public void ClearEvents()  
    {  
        SerializedProperty events = Get("events");  
  
        if (events != null && events.isArray)  
        {  
            events.ClearArray();  
        }  
    }  
  
    public int GetEventCount()  
    {  
        int ret = 0;  
  
        SerializedProperty curves = Get("events");  
  
        if (curves != null && curves.isArray)  
        {  
            ret = curves.arraySize;  
        }  
  
        return ret;  
    }  
  
    public void SetEvents(UnityEngine.AnimationEvent[] newEvents)  
    {  
        SerializedProperty events = Get("events");  
  
        if (events != null && events.isArray)  
        {  
            events.ClearArray();  
  
            foreach (UnityEngine.AnimationEvent evt in newEvents)  
            {  
                events.InsertArrayElementAtIndex(events.arraySize);  
                SetEvent(events.arraySize - 1, evt);  
            }  
        }  
    }  
  
    public UnityEngine.AnimationEvent[] GetEvents()  
    {
        UnityEngine.AnimationEvent[] ret = new UnityEngine.AnimationEvent[GetEventCount()];  
        SerializedProperty events = Get("events");  
  
        if (events != null && events.isArray)  
        {  
            for (int i = 0; i < GetEventCount(); ++i)  
            {  
                ret[i] = GetEvent(i);  
            }  
        }  
  
        return ret;  
  
    }  
  
}  


}